#pragma once
#include "InetAddr.hpp"
#include "Common.hpp"
#include "ThreadPool.hpp"
#include <sys/types.h>
#include "Socket.hpp"
#include <sys/wait.h>
#include <memory>
//#include "Cal.hpp"
//#include "Protocol.hpp"

namespace kzz
{
    //  远程执行命令模块，这里的传入函数应该是执行命令，
    // 要知道是谁要执行命令，执行什么命令，不需要知道文件描述符
    // using _func_t = std::function<void(int sockfd, InetAddr &_addr)>;
    // using _func_t = std::function<void(std::unique_ptr<Socket>&, InetAddr &_addr)>;
    //  翻译模块 ，不需要知道文件描述符，知道单词和客户端就行
   ////// using _func_t = std::function<std::string(const std::string &buffer, InetAddr &_addr)>;

     using server_func = std::function<void(std::shared_ptr<Socket> &client_fd, InetAddr &client_addr)>;
    class TcpServer : public NoCopy
    {
    public:
        //TcpServer(uint16_t port, _func_t func)
         TcpServer(uint16_t port)
            : _listensockfd(std::make_unique<TcpSocket>())
            , _port(port)
            , _isrunning(false)
          
        {
            _listensockfd->BuildTcpServerSocketMethod(port);
        }

        // 服务
        // void Service(std::shared_ptr<Socket> &client_fd, InetAddr &client_addr)
        // {          
        //     kzz::Cal cal;
        //     Protocol pro([&cal](kzz::Request &req)
        //                  {  return  cal.Execute(req);   });
        //     pro.GetRequest(client_fd, client_addr);
        // }

        // 服务器接受数据，然后处理完发回去
        void Start(server_func service)
        {
            _isrunning = true;
            int count=0;
            while (_isrunning)
            {
                //  using pro_task_t = std::function<void()>;
                // kzz::ThreadPool<pro_task_t> *tp = kzz::ThreadPool<pro_task_t>::GetInstance();
                // tp->Start();
                kzz::InetAddr client_addr;
                auto client_fd = _listensockfd->Accept(client_addr);
                if(client_fd==nullptr)
                {
                    LOG(LogLevel::DBUGER)<<"accept error";
                    continue;
                }

                //  std::cout<<"................."<<"fd:"<<client_fd->Fd()<<"............."<<std::endl;

                // std::cout<<"................."<<++count<<"............."<<std::endl;

                LOG(LogLevel::DBUGER)<<"服务器收到链接，客户端为"<<client_addr.Port();
                //vision 0:单进程版
                //Service(client_fd, client_addr);
                //// vision3: 线程池版
                // 来一个客户端就入池，把这个任务传给池
               
                // tp->Equeue([this, &client_fd, &client_addr]()
                //            { _service(client_fd, client_addr); });
                
                //     if (client_fd >= 0)
                //     {
                        //kzz::LOG(LogLevel::ERROR) << "accept success,sockfd:" << client_fd;
                        //vinson2:多线程版
                        // Thread th([this,&client_fd,&client_addr](){
                        //     Service(client_fd,client_addr);

                        // });
                        // //th.detach();
                        // th.Start();
                        // //th.detach();
                        // th.Join();

                //         // vision3: 线程池版
                //         // 来一个客户端就入池，把这个任务传给池
                //         //     using task_t=std::function<void()>;
                //         //    kzz::ThreadPool<task_t> *tp= kzz::ThreadPool<task_t>::GetInstance();
                //         //    tp->Start();
                //         //     tp->Equeue([this,&client_fd,&client_addr](){
                //         //         Service(client_fd,client_addr);
                //         //     });

                        //   vinson1：多进程版本
                        int pid = fork();
                        if (pid == 0)
                        {
                            // 子进程
                            //  接受客户端成功,开始接受客户端的传入数据
                            // 继续生成孙子进程
                            // 关闭不需要的文件描述符
                           /// close(_listensockfd);
                           // _listensockfd->Close();
                            int two_id = fork();
                            if (two_id == 0)
                            {
                                // 孙子进程
                                service(client_fd, client_addr);
                            }
                            else if (two_id < 0)
                            {
                                kzz::LOG(LogLevel::DBUGER) << "two fork fail";
                                exit(FORK_ERR);
                            }
                            else
                            {
                                // 子进程退出
                                kzz::LOG(LogLevel::DBUGER) << "two fork success";
                                exit(OK);
                            }
                        }
                        else if (pid < 0)
                        {
                            kzz::LOG(LogLevel::DBUGER) << "fork fail";
                            exit(FORK_ERR);
                        }
                        else
                        {
                            // 父进程
                            // 需要等待子进程，所以让孙子进程去干活，子进程直接wait，孙子变成孤儿，一号进程收养
                            // 关闭不需要的文件描述符，不需要客户端的文件描述符了
                           // close(client_fd);
                           // client_fd->Close();
                            int rid = wait(&pid);
                            (void)rid;
                        }
                   // }
                    // 这里返回值不会等于0，因为有默认的输入输出错误，除非自己关了
                //     else
                //     {
                //         // 接受失败
                //         kzz::LOG(LogLevel::ERROR) << "accept error";
                //         exit(ACCEPT_ERR);
                // }
            }
        }

    private:
        std::unique_ptr<Socket> _listensockfd;
        uint16_t _port;
        bool _isrunning;
       // server_func _service;
    };
}